import json

from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated

from backend.utils.base_serializer import SerializerFactory
from backend.utils.base_viewsets import BaseModelViewSet
from backend.utils.filters import CustomFilterBackend
from backend.utils.menu_tree import MenuTree
from backend.utils.pagination import CustomPagination
from backend.utils.response import ApiResponse
from permissions.models import Menu, Role
from permissions.permissions import AssignRolePermission
from permissions.serializers import MenuParentSerializer, MenuCreateSerializer, RoleSerializer, MenuTreeSerializer


class MenuViewSet(BaseModelViewSet):
    serializer_class = {
        'get_menu_list': MenuParentSerializer,
        'default': MenuCreateSerializer,
    }
    filter_backends = [CustomFilterBackend]
    search_fields = ['name', 'meta__title']
    queryset = Menu.advanced_objects.all()

    @action(methods=['GET'], detail=False, url_path='get_permission_code', url_name='get_permission_code',
            permission_classes=[IsAuthenticated])
    def get_permission_code(self, request):
        return ApiResponse(data=self.request.user.get_permission_code())

    @action(methods=['GET'], detail=False, url_path='get_menu_list', url_name='get_menu_list',
            permission_classes=[IsAuthenticated])
    def get_menu_list(self, request):
        router = MenuTree.make_router(self.get_queryset(), None)
        return ApiResponse(data=router)

    @action(methods=['GET'], detail=False, url_path='get_permission_tree', url_name='get_permission_tree',
            permission_classes=[IsAuthenticated])
    def get_permission_tree(self, request):
        queryset = Menu.advanced_objects.all()
        if self.request.user.is_superuser:
            menu_id_list = queryset.values_list('id', flat=True)
        else:
            menu_id_list = set([menu.id for role in self.request.user.roles.all() for menu in role.menus.all()])
        menu_tree = MenuTree.make_menu_tree(queryset, None, serializer_class=MenuTreeSerializer,
                                            menu_id_list=menu_id_list)
        return ApiResponse(data=menu_tree)

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        menu_tree = MenuTree.make_menu_tree(queryset, None)
        return ApiResponse(data=menu_tree)

    def get_queryset(self):
        user = self.request.user
        user_role_id_list = user.roles.all().values_list('id', flat=True)
        if user.is_superuser:
            self.queryset = self.queryset.order_by('orders').distinct()
        else:
            self.queryset = self.queryset.filter(roles__id__in=user_role_id_list).order_by('orders').distinct()
        if self.action == 'get_menu_list':
            self.queryset = self.queryset.exclude(type=2)
        status = self.request.query_params.get('status')
        if status:
            self.queryset = self.queryset.filter(status=json.loads(status))
        return self.queryset


class RoleModelViewSet(BaseModelViewSet):
    serializer_class = {
        'default': RoleSerializer,
        'permissions': SerializerFactory.build(Role, fields=['menus'])
    }
    filter_backends = [CustomFilterBackend]
    search_fields = ['name']
    queryset = Role.advanced_objects.all()
    pagination_class = CustomPagination

    def get_queryset(self):
        status = self.request.query_params.get('status')
        if status:
            self.queryset = self.queryset.filter(status=json.loads(status))
        return self.queryset.all()

    # 获取权限
    @action(methods=['GET'], detail=True, url_name='permissions', url_path='permissions',
            permission_classes=[IsAuthenticated, AssignRolePermission])
    def permissions(self, request, *args, **kwargs):
        role = self.get_object()
        serializer = self.get_serializer(role)
        return ApiResponse(data=serializer.data)

    # 分配权限
    @permissions.mapping.put
    def update_permissions(self, request, *args, **kwargs):
        # lst = [52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 36, 35, 34]
        role = self.get_object()
        menus = request.data.get('menus', [])
        if not menus:
            return ApiResponse(code=400, message='未选择需要分配的菜单')
        serializer = self.get_serializer(role, data=request.data)
        serializer.is_valid(raise_exception=True)
        new_menus = Menu.advanced_objects.filter(id__in=menus)
        if len(new_menus) != len(menus):
            return ApiResponse(code=400, message='传了不存在的菜单id')
        role.menus.set(new_menus)
        return ApiResponse(message='权限分配成功')
